package com.wxapp.common.core.annotation.resolver;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.wxapp.common.base.util.encryption.EncryptionUtil;
import com.wxapp.common.base.util.jackson.JacksonUtil;
import com.wxapp.common.base.util.md5.Md5Util;
import com.wxapp.common.constant.constant.LoginConstant;
import com.wxapp.common.constant.pojo.vo.UserVo;
import com.wxapp.common.constant.properties.LoginProperties;
import com.wxapp.common.core.annotation.User;
import com.wxapp.common.core.annotation.util.IpUtil;
import com.wxapp.common.core.filter.except.LoginException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.infra.instance.util.IpUtils;
import org.springframework.core.MethodParameter;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.util.Map;

/**
 * @author lgl
 */
@Component
@RequiredArgsConstructor
public class UserResolver implements HandlerMethodArgumentResolver {
    private final LoginProperties loginProperties;
    private final RedisTemplate redisTemplate;

    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return methodParameter.hasParameterAnnotation(User.class);
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        var methodAnnotation = methodParameter.getParameterAnnotation(User.class);
        boolean mast = methodAnnotation.defaulted();
        HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
        String token = request.getHeader(LoginConstant.INTERNAL_TOKEN_KEY);
        if (mast && (token == null || token.isEmpty())) {
            throw new LoginException("登录状态无效,请检查登录状态");
        }
        if (token == null || token.isEmpty()) {
            return null;
        }
        return dealToken(token,request);
    }

    /**
     * 解析token
     */
    private UserVo dealToken(String token, HttpServletRequest request) throws LoginException {
        String userInfoStr = null;
        try {
            String subject = JWT.require(Algorithm.HMAC256(loginProperties.getSecret())).build().verify(token).getSubject();
            userInfoStr = EncryptionUtil.aesDecrypt(Md5Util.md5(IpUtil.getIp(request)), subject);
        } catch (Exception e) {
            throw new LoginException();
        }
        if (userInfoStr == null) {
            throw new LoginException("登录状态无效,请检查登录状态");
        }
        var userVo = JacksonUtil.parseObject(userInfoStr, UserVo.class);
        if (userVo == null) {
            throw new LoginException("登录状态无效,请检查登录状态");
        }
        switch (userVo.getUserType()) {
            case WECHAT:
                Map<String, Object> custom = (Map<String, Object>) redisTemplate.opsForValue().get(LoginConstant.CUSTOM_OPENID + userVo.getId());
                if (custom != null) {
                    userVo.setCustomId((String) custom.get("customId"));
                    userVo.setOpenId((String) custom.get("openId"));
                }
                break;
            case WEB:
            default:
                break;
        }
        return userVo;
    }
}
